﻿using DotNetExtensions.AspNet;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AspNetSimple
{
    public delegate void ImageConvertHandler(Bitmap bitmap);
    public class WebBrowserConvert : Singleton<WebBrowserConvert>
    {
        private readonly MyWebBrowser browser;
        public event ImageConvertHandler Completed;
        private WebBrowserConvert()
        {
            browser = new MyWebBrowser();
            browser.Size = new Size(1366, 768);
            browser.DocumentCompleted += (sender, e) =>
            {
                var wb = sender as MyWebBrowser;
                int width = wb.Document.Body.ScrollRectangle.Width;
                int height = wb.Document.Body.ScrollRectangle.Height;

                wb.Width = width;
                wb.Height = height;

                WebControlImage.Snapshot snap = new WebControlImage.Snapshot();
                Bitmap MyImage = snap.TakeSnapshot(wb.ActiveXInstance, new Rectangle(0, 0, width, height));

                Completed?.Invoke(MyImage);
            };
        }
        public void ToBitmap(Uri uri)
        {
            browser.Navigate(uri);
        }

        private class WebControlImage
        {
            internal static class NativeMethods
            {
                [StructLayout(LayoutKind.Sequential)]
                public sealed class TagDVTARGETDEVICE
                {
                    [MarshalAs(UnmanagedType.U4)]
                    public int tdSize;
                    [MarshalAs(UnmanagedType.U2)]
                    public short tdDriverNameOffset;
                    [MarshalAs(UnmanagedType.U2)]
                    public short tdDeviceNameOffset;
                    [MarshalAs(UnmanagedType.U2)]
                    public short tdPortNameOffset;
                    [MarshalAs(UnmanagedType.U2)]
                    public short tdExtDevmodeOffset;
                }
                [StructLayout(LayoutKind.Sequential)]
                public class COMRECT
                {
                    public int left;
                    public int top;
                    public int right;
                    public int bottom;
                    public COMRECT() { }

                    public COMRECT(Rectangle r)
                    {
                        this.left = r.X;
                        this.top = r.Y;
                        this.right = r.Right;
                        this.bottom = r.Bottom;
                    }

                    public COMRECT(int left, int top, int right, int bottom)
                    {
                        this.left = left;
                        this.top = top;
                        this.right = right;
                        this.bottom = bottom;
                    }
                    public static COMRECT FromXYWH(int x, int y, int width, int height)
                    {
                        return new COMRECT(x, y, x + width, y + height);
                    }
                    public override string ToString()
                    {
                        return string.Concat(new object[] { "Left = ", this.left, " Top ", this.top, " Right = ", this.right, " Bottom = ", this.bottom });
                    }
                }
                [StructLayout(LayoutKind.Sequential)]
                public sealed class TagLOGPALETTE
                {
                    [MarshalAs(UnmanagedType.U2)]
                    public short palVersion;
                    [MarshalAs(UnmanagedType.U2)]
                    public short palNumEntries;
                }
            }
            public class Snapshot
            {
                public Bitmap TakeSnapshot(object pUnknown, Rectangle bmpRect)
                {
                    if (pUnknown == null || !Marshal.IsComObject(pUnknown) || bmpRect.Width == 0) return null;

                    UnsafeNativeMethods.IViewObject ViewObject = null;
                    Bitmap pPicture = new Bitmap(bmpRect.Width, bmpRect.Height);
                    Graphics hDrawDC = Graphics.FromImage(pPicture);

                    IntPtr pViewObject;
                    object hret = Marshal.QueryInterface(Marshal.GetIUnknownForObject(pUnknown),
ref UnsafeNativeMethods.IID_IViewObject, out pViewObject);
                    try
                    {
                        ViewObject = Marshal.GetTypedObjectForIUnknown(pViewObject, typeof(UnsafeNativeMethods.IViewObject)) as UnsafeNativeMethods.IViewObject;
                        ViewObject.Draw((int) DVASPECT.DVASPECT_CONTENT,-1,IntPtr.Zero,null,IntPtr.Zero,hDrawDC.GetHdc(),new NativeMethods.COMRECT(bmpRect), null,IntPtr.Zero,0);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        throw ex;
                    }
                    //释放
                    hDrawDC.Dispose();
                    return pPicture;
                }
            }
            [SuppressUnmanagedCodeSecurity]
            internal static class UnsafeNativeMethods
            {
                public static Guid IID_IViewObject = new Guid("{0000010d-0000-0000-C000-000000000046}");
                [ComImport, Guid("0000010d-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
                public interface IViewObject
                {
                    [PreserveSig]
                    int Draw([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [In] NativeMethods.TagDVTARGETDEVICE ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, [In] NativeMethods.COMRECT lprcBounds, [In] NativeMethods.COMRECT lprcWBounds, IntPtr pfnContinue, [In] int dwContinue);
                    [PreserveSig]
                    int GetColorSet([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [In] NativeMethods.TagDVTARGETDEVICE ptd, IntPtr hicTargetDev, [Out] NativeMethods.TagLOGPALETTE ppColorSet);
                    [PreserveSig]
                    int Freeze([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [Out] IntPtr pdwFreeze);
                    [PreserveSig]
                    int Unfreeze([In, MarshalAs(UnmanagedType.U4)] int dwFreeze);
                    void SetAdvise([In, MarshalAs(UnmanagedType.U4)] int aspects, [In, MarshalAs(UnmanagedType.U4)] int advf, [In, MarshalAs(UnmanagedType.Interface)] IAdviseSink pAdvSink);
                    void GetAdvise([In, Out, MarshalAs(UnmanagedType.LPArray)] int[] paspects, [In, Out, MarshalAs(UnmanagedType.LPArray)] int[] advf, [In, Out, MarshalAs(UnmanagedType.LPArray)] IAdviseSink[] pAdvSink);
                }
            }
        }
    }
}
